# -*- coding: utf-8 -*-
'''
储存和使用裁决数据
裁决表7.1.4、7.1.6
'''

__author__ = 'Yu XH'

import numpy as np

from myAI.const import *


class Probability:
    """裁决中用到的随机数的概率，向量和矩阵的索引分别表示2~12的随机数"""
    vector_1d = np.array([0.0278, 0.0556, 0.0833, 0.1111, 0.1389, 0.1667, 0.1389, 0.1111, 0.0833, 0.0556, 0.0278]).\
        reshape(-1, 1)  # 一维列向量
    matrix_2d = vector_1d.T * vector_1d  # 11*11的矩阵


class CombatResultsVehicleDirect(object):
    """表7.1.4 直瞄武器对车辆单位战斗结果"""
    def __init__(self):
        # combat_results_mean[3, 2]表示攻击等级=3+1=4，车数=2+1=3的战斗结果向量，见表7.1.4
        self.combat_results = np.array(
            [[[1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0.],
              [0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0.], [0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0.]],
             [[0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0.], [0., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0.],
              [0., 0., 1., 1., 1., 0., 0., 0., 0., 0., 0.], [0., 0., 1., 1., 1., 0., 0., 0., 0., 0., 0.]],
             [[0., 1., 1., 1., 0., 0., 0., 0., 0., 0., 0.], [0., 0., 0., 1., 1., 1., 0., 0., 0., 0., 0.],
              [1., 1., 0., 1., 1., 1., 0., 0., 0., 0., 0.], [1., 1., 0., 1., 1., 1., 0., 0., 0., 0., 0.]],
             [[0., 0., 1., 1., 1., 0., 0., 0., 0., 0., 0.], [1., 1., 0., 1., 1., 1., 0., 0., 0., 0., 0.],
              [1., 0., 1., 1., 1., 1., 1., 0., 0., 0., 0.], [1., 0., 1., 1., 1., 2., 1., 0., 0., 0., 0.]],
             [[0., 0., 0., 1., 1., 1., 0., 0., 0., 0., 0.], [1., 0., 1., 1., 1., 1., 1., 0., 0., 0., 0.],
              [1., 1., 1., 1., 1., 2., 1., 1., 0., 0., 0.], [1., 1., 1., 1., 1., 2., 0., 2., 0., 2., 0.]],
             [[1., 1., 0., 1., 1., 1., 0., 0., 0., 0., 0.], [1., 0., 1., 1., 1., 2., 1., 0., 0., 0., 0.],
              [1., 1., 1., 1., 1., 2., 0., 2., 1., 2., 0.], [1., 1., 1., 1., 1., 2., 2., 2., 2., 0., 0.]],
             [[1., 0., 1., 1., 1., 1., 1., 0., 0., 0., 0.], [1., 1., 1., 1., 1., 2., 1., 1., 0., 0., 0.],
              [1., 1., 1., 1., 1., 2., 2., 2., 2., 0., 0.], [1., 1., 1., 1., 1., 3., 2., 2., 2., 0., 1.]],
             [[1., 0., 1., 1., 1., 2., 1., 0., 0., 0., 0.], [1., 1., 1., 1., 1., 2., 0., 2., 1., 2., 0.],
              [1., 1., 1., 1., 1., 3., 2., 2., 2., 0., 1.], [2., 2., 1., 1., 1., 3., 2., 2., 2., 2., 2.]],
             [[1., 1., 1., 1., 1., 2., 0., 2., 0., 2., 0.], [1., 1., 1., 1., 1., 2., 2., 2., 2., 0., 0.],
              [2., 2., 1., 1., 1., 3., 2., 2., 2., 2., 2.], [3., 3., 1., 1., 1., 4., 2., 2., 2., 3., 3.]],
             [[1., 1., 1., 1., 1., 2., 0., 2., 1., 2., 0.], [1., 1., 1., 1., 1., 3., 2., 2., 2., 0., 1.],
              [3., 3., 1., 1., 1., 3., 2., 2., 2., 3., 3.], [2., 2., 1., 1., 1., 3., 4., 4., 4., 2., 3.]]])

    def get_combat_results(self, attack_level, blood=3):
        """
        输出战斗结果的向量或者矩阵，如果attack_level和blood都是narray，那么它们的shape需要一致
        :param attack_level: {int/narray} 攻击等级，支持多个攻击等级一起计算
        :param blood: {int/narray} 车数
        :return: n*11的矩阵，其中n=len(attack_level)
        """
        return self.combat_results[attack_level-1, blood-1]


class DamageRectVehicleDirect(object):
    """表7.1.5 车辆战损结果修正"""
    def __init__(self):
        self.composite_armor_rects = np.array([-3]*9 + [-2]*2 + [-1]*3 + [0]*5 + [1] + [2]*11)
        self.heavy_armor_rects = np.array([-3]*6 + [-2]*2 + [-1]*2 + [0]*8 + [1] + [2]*12)
        self.medium_armor_rects = np.array([-2]*6 + [-1]*2 + [0]*9 +[1]*2 + [2] + [3]*11)
        self.light_armor_rects = np.array([-1]*6 + [0]*8 + [1]*4 + [2]*2 + [3]*11)
        self.no_armor_rects = np.array([0]*11 + [1]*7 + [2]*2 + [3]*11)
        self.damage_rect_matrix = np.concatenate((self.no_armor_rects.reshape(1, -1),
                                                  self.light_armor_rects.reshape(1, -1),
                                                  self.medium_armor_rects.reshape(1, -1),
                                                  self.heavy_armor_rects.reshape(1, -1),
                                                  self.composite_armor_rects.reshape(1, -1)), axis=0)

    def get_damage_rects(self, armor_type, rect_value=0):
        """
        根据装甲类型armor_type和随机数修正值rect_value，获取用于战损结果修正的矩阵
        :param armor_type: {int/narray} 装甲类型
        :param rect_value: {int/narray} 修正值，当armor_type和rect_value都是数组时，它们shape要相同
        :return:
        """
        return self.damage_rect_matrix[armor_type, rect_value+10:rect_value+21]

    def calc_rect_value(self, att_terrain=TerrainType.OpenLand, att_keep=0, att_speed=0,
                        tar_terrain=TerrainType.OpenLand, tar_move_state=MoveState.Common, tar_speed=0, tar_stack=0):
        """根据进攻算子和目标算子的地形和状态，计算出随机数修正值rect_value"""
        rect_value = 0
        if att_keep == 1:
            rect_value += -1
        if att_speed > 0:
            rect_value += -1
        if att_terrain == TerrainType.Water:
            rect_value += -1
        if tar_terrain == TerrainType.Resident:
            rect_value += -1
        elif tar_terrain == TerrainType.Forest or tar_terrain == TerrainType.Water:
            rect_value += -2
        if tar_move_state == MoveState.Shelter:
            rect_value += -2
        if tar_speed > 0:
            if tar_move_state == MoveState.Common:
                rect_value += -2
            elif tar_move_state == MoveState.March:
                rect_value += 4
        if tar_stack == 1:
            rect_value += 2
        return rect_value


class CombatResultsInfantryDirect(object):
    """表7.1.6 直瞄武器对人员/步兵轻武器对车辆战斗结果表"""
    def __init__(self):
        # combat_results[0]表示未被压制的战斗结果表，combat_results[1]表示被压制的
        self.combat_results = np.array([[[0, 0, 0, 0, 1, 2, 2, 2, 2, 2],
                                         [0, 0, 0, 0, 0, 1, 1, 1, 1, 1],
                                         [0, 0, 0, 0, 0, 0, 0, 1, 1, 1],
                                         [0, 0, 0, 0, 0, 0, 0, 0, 1, 1],
                                         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                                         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                                         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                                         [0, 0, 0, 0, 0, 0, 0, 0, 0, 1],
                                         [0, 0, 0, 0, 0, 0, 0, 0, 1, 1],
                                         [0, 0, 0, 0, 0, 0, 0, 1, 1, 2],
                                         [0, 0, 0, 0, 0, 1, 2, 2, 2, 2]],
                                        [[1, 1, 1, 1, 1, 2, 2, 2, 2, 2],
                                         [0, 1, 1, 1, 1, 1, 1, 1, 1, 1],
                                         [0, 0, 1, 1, 1, 1, 1, 1, 1, 1],
                                         [0, 0, 0, 0, 1, 1, 1, 1, 1, 1],
                                         [0, 0, 0, 0, 0, 1, 1, 1, 1, 1],
                                         [0, 0, 0, 0, 0, 0, 1, 1, 1, 1],
                                         [0, 0, 0, 0, 0, 0, 1, 1, 1, 1],
                                         [0, 0, 0, 0, 0, 1, 1, 1, 1, 1],
                                         [0, 0, 0, 1, 1, 1, 1, 1, 1, 1],
                                         [0, 1, 1, 1, 1, 1, 1, 1, 1, 2],
                                         [1, 1, 1, 1, 1, 1, 2, 2, 2, 2]]])

    def get_combat_results(self, attack_level, keep=0):
        """
        输出战斗结果的向量
        :param attack_level: {int} 攻击等级
        :return: 战斗结果的向量
        """
        return self.combat_results[keep][:, attack_level-1]


class DamageRectInfantryDirect(object):
    """表7.1.7 人员损耗结果修正"""
    def __init__(self):
        self.damage_rect_vec = np.array([-1]*9 + [0]*7 + [1]*15)

    def get_damage_rects(self, rect_value=0):
        """
        根据装甲类型armor_type和随机数修正值rect_value，获取用于战损结果修正的矩阵
        :param armor_type: {int/narray} 装甲类型
        :param rect_value: {int/narray} 修正值，当armor_type和rect_value都是数组时，它们shape要相同
        :return:
        """
        return self.damage_rect_vec[rect_value+10:rect_value+21]

    def calc_rect_value(self, att_keep=0, att_speed=0, tar_terrain=TerrainType.OpenLand,
                        tar_move_state=MoveState.Common, tar_speed=0, tar_stack=0):
        """根据进攻算子和目标算子的地形和状态，计算出随机数修正值rect_value"""
        rect_value = 0
        if att_keep == 1:
            rect_value += -1
        if att_speed > 0:
            rect_value += -1
        if tar_terrain == TerrainType.Resident:
            rect_value += -1
        elif tar_terrain == TerrainType.Forest:
            rect_value += -2
        if tar_move_state == MoveState.Shelter:
            rect_value += -2
        if tar_speed > 0:
            if tar_move_state == MoveState.Common:
                rect_value += -2
            elif tar_move_state == MoveState.March:
                rect_value += 4
        if tar_stack == 1:
            rect_value += 2
        return rect_value


class DamageAircraft:
    KillProb = np.array([0, 0.027777778, 0.055555556, 0.111111111, 0.166666667, 0.25, 0.333333333, 0.444444444,
                         0.555555556, 0.694444444, 0.833333333, 1])
